//
//  CWNetWork.m
//  CWDevelop
//
//  Created by LittoCats on 7/15/14.
//  Copyright (c) 2014 Littocats. All rights reserved.
//

#import "CWNetWork.h"
#import "AFNetworking.h"
#import "UIKit+AFNetworking.h"

#import "GCDAsyncUdpSocket.h"

#import <objc/message.h>

#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>

#define IOS_CELLULAR    @"pdp_ip0"
#define IOS_WIFI        @"en0"
#define IP_ADDR_IPv4    @"ipv4"
#define IP_ADDR_IPv6    @"ipv6"

@implementation CWNetWork

+ (void)get:(NSString *)urlString params:(NSDictionary *)params completionHandler:(void (^)(NSDictionary *, NSError *))handler
{
    Class http = NSClassFromString(@"AFHTTPRequestOperationManager");
    id manager ;
    if ([http respondsToSelector:NSSelectorFromString(@"manager")])
        manager = objc_msgSend(http, NSSelectorFromString(@"manager"));
    if ([manager respondsToSelector:NSSelectorFromString(@"GET:parameters:success:failure:")])
        objc_msgSend(manager, NSSelectorFromString(@"GET:parameters:success:failure:"),
                     urlString,
                     params,
                     ^(AFHTTPRequestOperation *operation, id responseObject) {
                         if (handler)
                             handler(responseObject,responseObject ? nil : [NSError errorWithDomain:@"系统错误！"
                                                                                               code:0
                                                                                           userInfo:nil]);
                     },
                     ^(AFHTTPRequestOperation *operation, NSError *error) {
                         if (handler)
                             handler(nil, error);
                     });
}

+ (void)post:(NSString *)urlString params:(NSDictionary *)params completionHandler:(void (^)(NSDictionary *, NSError *))handler
{
    [[self manager] POST:urlString parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
        if (handler)
            handler(responseObject,responseObject ? nil : [NSError errorWithDomain:@"系统错误！"
                                                                              code:0
                                                                          userInfo:nil]);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        if (handler)
            handler(nil, error);
    }];
}

+ (void)download:(NSString *)urlString params:(NSDictionary *)params completionHandler:(void (^)(NSString *, NSError *))handler
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableString *parameterString = [NSMutableString new];
    for (NSString *parameterKey in [params allKeys]) {
        parameterString.length ? [parameterString appendString:[NSString stringWithFormat:@"&%@=%@",parameterKey,params[parameterKey]]] :
        [parameterString appendString:[NSString stringWithFormat:@"%@=%@",parameterKey,params[parameterKey]]];
    }
    url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@%@",urlString, [url query] ? @"&" : @"?", parameterString]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    NSString *tempPath = [NSString stringWithFormat:@"%@downloadtemp%p",NSTemporaryDirectory(),request];
    
    AFHTTPRequestOperation *download = [[self manager] HTTPRequestOperationWithRequest:request
                                                                               success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                                                                   NSError *error;
                                                                                   NSString *downloadPath = [NSString stringWithFormat:@"%@%@",NSTemporaryDirectory(),[operation.response suggestedFilename]];
                                                                                   if ([[NSFileManager defaultManager] fileExistsAtPath:downloadPath])
                                                                                       [[NSFileManager defaultManager] removeItemAtPath:downloadPath error:&error];
                                                                                   
                                                                                   [[NSFileManager defaultManager] moveItemAtPath:tempPath toPath:downloadPath error:&error];
                                                                                   if (handler)
                                                                                       handler(downloadPath, error ? error : nil);
                                                                                   
                                                                               } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                                                   if (handler)
                                                                                       handler(nil, error);
                                                                               }];
    download.outputStream = [NSOutputStream outputStreamToFileAtPath:tempPath append:NO];
    
    [[self manager].operationQueue addOperation:download];
}

+ (AFHTTPRequestOperationManager *)manager
{
    static AFHTTPRequestOperationManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [AFHTTPRequestOperationManager manager];
    });
    return manager;
}

+ (void)analyseDebugServer:(void (^)(NSURL *))completionHandler
{
    [CWNetWorkDebugger analyseDebugServer:completionHandler];
}

#pragma mark- utilies
+ (NSString *)getIPAddress:(BOOL)preferIPv4
{
    NSArray *searchArray = preferIPv4 ?
    @[ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :
    @[ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
    
    NSDictionary *addresses = [self getIPAddresses];
    
    __block NSString *address;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
     {
         address = addresses[key];
         if(address) *stop = YES;
     } ];
    return address ? address : @"0.0.0.0";
}

+ (NSDictionary *)getIPAddresses
{
    NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
    
    // retrieve the current interfaces - returns 0 on success
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces)) {
        // Loop through linked list of interfaces
        struct ifaddrs *interface;
        for(interface=interfaces; interface; interface=interface->ifa_next) {
            if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                continue; // deeply nested code harder to read
            }
            const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
            char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
            if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
                NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                NSString *type;
                if(addr->sin_family == AF_INET) {
                    if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv4;
                    }
                } else {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                    if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv6;
                    }
                }
                if(type) {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        // Free memory
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}

+ (void)ping:(NSString *)urlString handler:(void (^)(NSString *))handler
{
    
}
@end

@interface CWNetWorkDebugger ()

@property (nonatomic, strong) NSMutableArray *handlers;

@property (nonatomic, strong) GCDAsyncUdpSocket *udpSocket;

@property (nonatomic, strong) NSURL *debugURL;
@end

@implementation CWNetWorkDebugger

+ (void)analyseDebugServer:(void (^)(NSURL *))completionHandler
{
    if (completionHandler){
        if (![[self defaultDebugger] debugURL]){
            [[[self defaultDebugger] handlers] addObject:completionHandler];
            [[self defaultDebugger] setupSocket];
        }
        else
            completionHandler([[self defaultDebugger] debugURL]);
    }
}

+ (instancetype)defaultDebugger
{
    static CWNetWorkDebugger *debugger = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        debugger = [CWNetWorkDebugger new];
    });
    return debugger;
}

- (id)init
{
    self = [super init];
    if (self) {
        self.handlers = [NSMutableArray new];
    }
    return self;
}
- (void)setupSocket
{
	// Setup our socket.
	// The socket will invoke our delegate methods using the usual delegate paradigm.
	// However, it will invoke the delegate methods on a specified GCD delegate dispatch queue.
	//
	// Now we can configure the delegate dispatch queues however we want.
	// We could simply use the main dispatc queue, so the delegate methods are invoked on the main thread.
	// Or we could use a dedicated dispatch queue, which could be helpful if we were doing a lot of processing.
	//
	// The best approach for your application will depend upon convenience, requirements and performance.
	//
	// For this simple example, we're just going to use the main thread.
	
	self.udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    

	
	NSError *error = nil;
	
	if (![_udpSocket bindToPort:3001 error:&error])
	{
        NSLog(@"Error binding: %@", error);
		return;
	}
	if (![_udpSocket beginReceiving:&error])
	{
        NSLog(@"Error receiving: %@", error);
		return;
	}
	
    NSLog(@"Ready");
    NSLog(@"%@",    _udpSocket.localHost);
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
	NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
	if (msg)
	{
        NSURL *url = [NSURL URLWithString:msg];
        self.debugURL = url;
        //关闭UPD
        [sock pauseReceiving];
        [sock close];
        while ([_handlers firstObject]) {
            void (^handler)(NSURL *) = [_handlers firstObject];
            handler(url);
            [_handlers removeObjectAtIndex:0];
        }
	}
	else
	{
		NSString *host = nil;
		uint16_t port = 0;
		[GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];
		
        NSLog(@"RECV: Unknown message from: %@:%hu", host, port);
	}
}
@end
@implementation UIImageView (CWNet)

- (void)setImageURL:(NSURL *)imageURL
    withPlaceholder:(UIImage *)placeholder
  completionHandler:(void (^)(UIImage *))handler
{
    
}

@end